﻿; (function (global) {

    'use strict';

    global.BackTrakingSolver = function BackTrakingSolver(options) {
        this.options = options;
        this.trialsPerIndex = [];
    }

    BackTrakingSolver.prototype.solve = function (grid) {
        var emptyCells = GridHelper.getCellsOfValue(grid, 0);
        var emptyLength = emptyCells.length;
        if (emptyLength === 0) {
            return 1;
        }

        SolvingHelper.fillCandidates(grid);
        emptyCells.sort(function (a, b) { return a.candidates.count - b.candidates.count; });

        var solutionCount = 0;
        this.trialsPerIndex.clear();

        for (var i = 0; i < emptyLength; i++) {
            var cell = emptyCells[i];
            this.trialsPerIndex[i] = cell.candidates.values.slice();
            if (this.options.shuffle)
                this.trialsPerIndex[i].shuffle();
        }

        var index = 0;
        mainLoop: while (true) {
            var trials = this.trialsPerIndex[index];
            var cell = emptyCells[index];
            index++;
            trialLoop:
                while (trials.length > 0) {
                    var k = trials.pop();
                    if (SolvingHelper.isCandidateEligible(k, cell.indices, grid)) {
                        cell.value = k;
                        if (index === emptyLength) {
                            solutionCount++;
                            if (!this.options.allSolutions || solutionCount === 2) {
                                break mainLoop;
                            }

                            break trialLoop;
                        }
                        continue mainLoop;
                    }
                }
            index--;
            rewindLoop:
                while (index > -1) {
                    var trialsLength = this.trialsPerIndex[index].length;
                    var cell = emptyCells[index];
                    cell.value = 0;
                    if (trialsLength > 0) {
                        continue mainLoop;
                    }
                    else {
                        var trials = this.trialsPerIndex[index];
                        trials.pushArray(cell.candidates.values);
                        //for (var i = 0; i < cell.candidates.count; i++) { trials.push(cell.candidates.values[i]); }
                        if (this.options.shuffle)
                            trials.shuffle();
                    }
                    index--;
                }

            break mainLoop;
        }

        // clear candidates for filled cells
        SolvingHelper.fillCandidates(grid);
        return solutionCount;
    }

}(this));
